#include "plot.h"

static gnuplot_ctrl* PLOT_initWin(plot* plot, ctrl* ctrl);
static int PLOT_finalizeWin(gnuplot_ctrl *h, ctrl* ctrl);
static int PLOT_singledraw(plot* plot, ctrl* ctrl);
static int PLOT_multipledraw(plot* plot, ctrl* ctrl, char**);
static int PLOT_setOutput(gnuplot_ctrl *h,ctrl* ctrl);
static int PLOT_setStyle(gnuplot_ctrl *h,int style);

int PLOT_setStyle(gnuplot_ctrl *h,int style){
  if(style != PLOT_DEFAULT){
    switch(style){
    case PLOT_LINES:
      gnuplot_setstyle(h, "lines");
      break;
    case PLOT_LINESPOINTS:
      gnuplot_setstyle(h, "linespoints");
      break;
    case PLOT_POINTS:
      gnuplot_setstyle(h, "points");
      break;
    case PLOT_HISTEPS:
      gnuplot_setstyle(h, "histeps");
      break;
    case PLOT_BOXES:
      gnuplot_setstyle(h, "boxes");
      break;
    }
  }
  return 1;
}

int PLOT_draw(plot* plot, ctrl* ctrl, char **names){
  if(ctrl->multiple_win == NO){
    return PLOT_singledraw(plot, ctrl);
  }else{
    plot->max_w = MAX_WINS;
    plot->w = 0;
    plot->wins = U_malloc(plot->max_w,gnuplot_ctrl *,"PLOT_draw error code 1\n");
    return PLOT_multipledraw(plot, ctrl, names);
  }
}
int PLOT_multipledraw(plot* plot, ctrl* ctrl, char** names){
  int i,j;
  gnuplot_ctrl *h;
  char *buf,buf2[256];
  double min_x = -1.0,max_x = 0.0;
  double range_x[2];
  double min,max,avg,stddev;
  int min_p,max_p;

  for(i=0;i<plot->nbdat;i++){
    for(j=0;j<plot->dat[i].nb;j++){
      if(plot->dat[i].x[j] < min_x || min_x == -1.0)
	min_x = plot->dat[i].x[j];
      if(plot->dat[i].x[j] > max_x)
	max_x = plot->dat[i].x[j];
    } 
  }
  range_x[0] = min_x;
  range_x[1] = max_x;
  
  for(i=0;i<plot->nbdat;i++){
    buf = ctrl->plot_file;
    if(names != NULL){
      strcpy(buf2,names[i]);
      strcat(buf2,ctrl->plot_file);
      ctrl->plot_file = buf2;
    }
    h = PLOT_initWin(plot,ctrl);
    PLOT_setOutput(h,ctrl);
    ctrl->plot_file = buf;
    plot->wins[plot->w++] = h;
    PLOT_setStyle(h,plot->dat[i].style);
  }

  printf("------------------------------------------------------------------------------------------------------------------\n");
  printf("| %32s | %10s | %10s | %10s | %10s | %10s | %10s |\n","","min","","max","","avg","stddev");
  printf("------------------------------------------------------------------------------------------------------------------\n");
  for(i=0;i<plot->w;i++){
    h = plot->wins[i];
    if(plot->dat[i].z == NULL){
      gnuplot_plot_xy(h,plot->dat[i].x,plot->dat[i].y,plot->dat[i].nb,plot->dat[i].title,range_x,NULL);
      U_dbStat(plot->dat[i].x,plot->dat[i].nb,&min,&min_p,&max,&max_p,&avg,&stddev,NULL);
      printf("| %30s X | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f |\n",
	     plot->dat[i].title,min,plot->dat[i].y[min_p],max,plot->dat[i].y[max_p],avg,stddev);
      U_dbStat(plot->dat[i].y,plot->dat[i].nb,&min,&min_p,&max,&max_p,&avg,&stddev,NULL);
      printf("| %30s Y | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f |\n",
	     "",min,plot->dat[i].x[min_p],max,plot->dat[i].x[max_p],avg,stddev);
    }else
      gnuplot_plot_xyz(h,plot->dat[i].x,plot->dat[i].y,plot->dat[i].z,plot->dat[i].nb,plot->dat[i].title,range_x,NULL);
    PLOT_finalizeWin(h,ctrl);
  }
  printf("------------------------------------------------------------------------------------------------------------------\n");
  return 1;
  
}

int PLOT_setOutput(gnuplot_ctrl *h,ctrl* ctrl){
  switch(ctrl->plot_out){
  case PNG:
    gnuplot_cmd(h, "set terminal png notransparent");
    gnuplot_cmd(h, "set output \"%s\"",ctrl->plot_file);
    break;
  case PS:
    gnuplot_cmd(h, "set terminal postscript color solid");
    gnuplot_cmd(h, "set output \"%s\"",ctrl->plot_file);
    break;
  case EPS:
    gnuplot_cmd(h, "set terminal postscript eps color solid");
    gnuplot_cmd(h, "set output \"%s\"",ctrl->plot_file);
    break;
  case PDF:
    gnuplot_cmd(h, "set terminal pdf");
    gnuplot_cmd(h, "set output \"%s\"",ctrl->plot_file);
    break;
  }
  return 1;
}

gnuplot_ctrl* PLOT_initWin(plot* plot, ctrl* ctrl){
  gnuplot_ctrl *h;
  h = gnuplot_init();

  gnuplot_set_time(h);
  gnuplot_set_title(h,plot->title);
  gnuplot_set_xlabel(h,plot->xlabel);
  gnuplot_set_ylabel(h,plot->ylabel);
  if(!plot->border)
    gnuplot_cmd(h, "set noborder");
  if(plot->grid)
    gnuplot_cmd(h, "set grid");
  if(!plot->key)
    gnuplot_cmd(h, "set nokey");
  if(!plot->xtics)
    gnuplot_cmd(h, "set noxtics");
  if(!plot->ytics)
    gnuplot_cmd(h, "set noytics");
  
  return h;
}
int PLOT_finalizeWin(gnuplot_ctrl *h, ctrl* ctrl){
  if(ctrl->plot_out != STDOUT){
    gnuplot_cmd(h, "set output");
    gnuplot_cmd(h, "set terminal x11");
    gnuplot_cmd(h, "replot");
  }
  return 1;
}
int PLOT_singledraw(plot* plot, ctrl* ctrl){
  int i,j;
  gnuplot_ctrl *h;
  double min_x = -1.0,max_x = 0.0;
  double range_x[2];
  double min,max,avg,stddev;
  int min_p,max_p;

  h = PLOT_initWin(plot,ctrl);
  
  plot->win = h;
  for(i=0;i<plot->nbdat;i++){
    for(j=0;j<plot->dat[i].nb;j++){
      if(plot->dat[i].x[j] < min_x || min_x == -1.0)
	min_x = plot->dat[i].x[j];
      if(plot->dat[i].x[j] > max_x)
	max_x = plot->dat[i].x[j];
    } 
  }
  range_x[0] = min_x;
  range_x[1] = max_x;
  
  printf("------------------------------------------------------------------------------------------------------------------\n");
  printf("| %32s | %10s | %10s | %10s | %10s | %10s | %10s |\n","","min","","max","","avg","stddev");
  printf("------------------------------------------------------------------------------------------------------------------\n");
  for(i=0;i<plot->nbdat;i++){
    PLOT_setStyle(h,plot->dat[i].style);
    if(i == plot->nbdat-1){
      PLOT_setOutput(h,ctrl);
    }
    if(plot->dat[i].z == NULL){
      gnuplot_plot_xy(h,plot->dat[i].x,plot->dat[i].y,plot->dat[i].nb,plot->dat[i].title,range_x,NULL);
      U_dbStat(plot->dat[i].x,plot->dat[i].nb,&min,&min_p,&max,&max_p,&avg,&stddev,NULL);
      printf("| %30s X | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f |\n",
	     plot->dat[i].title,min,plot->dat[i].y[min_p],max,plot->dat[i].y[max_p],avg,stddev);
      U_dbStat(plot->dat[i].y,plot->dat[i].nb,&min,&min_p,&max,&max_p,&avg,&stddev,NULL);
      printf("| %30s Y | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f | %10.2f |\n",
	     "",min,plot->dat[i].x[min_p],max,plot->dat[i].x[max_p],avg,stddev);
    }else{
      gnuplot_plot_xyz(h,plot->dat[i].x,plot->dat[i].y,plot->dat[i].z,plot->dat[i].nb,plot->dat[i].title,range_x,NULL);
    }
  }
  printf("------------------------------------------------------------------------------------------------------------------\n");
  
  PLOT_finalizeWin(h,ctrl);

  return 1;
}

plot *PLOT_xy(double** x,double** y, char** fields, int* id_fields, int nb, char *xlabel,char *ylabel,char *title,int border,int grid,int key,int xtics,int ytics){
  data *dat;
  plot *p;
  int field;

  p = U_malloc (1,plot,"PLOT_xy code 1\n");
  p->xlabel = xlabel;
  p->ylabel = ylabel;
  p->title  = title;
  p->border = border;
  p->grid   = grid;
  p->key    = key;
  p->xtics  = xtics;
  p->ytics  = ytics;
  p->nbdat  = nb;
  p->wins   = NULL;

  dat = U_malloc (nb,data,"PLOT_xy error code 2\n");
  for(field=0;field<nb;field++){
    dat[field].pdata = NULL;
    dat[field].nb = x[field][0];
    dat[field].x = &(x[field][1]);
    dat[field].y = &(y[field][1]);
    dat[field].z = NULL;
    dat[field].title = fields[id_fields[field]];
    dat[field].style = PLOT_LINESPOINTS;
  }
  p->dat = dat;
  return p;
}

plot *PLOT_getDistribution(double **datas,int nb_bars,char **fields,int* id_fields,int nb_fields,char *xlabel,char *ylabel,char *title,int border,int grid,int key,int xtics,int ytics){
  plot *p;
  data *dat;
  int field,nb_pt,i;
  double min=-1,max=0.0,delta;
  double *x, *y;
  double *d;

  p = U_malloc(1,plot,"PLOT_getDistribution error code 1\n");
  
  p->xlabel = xlabel;
  p->ylabel = ylabel;
  p->title  = title;
  p->border = border;
  p->grid   = grid;
  p->key    = key;
  p->xtics  = xtics;
  p->ytics  = ytics;
  p->nbdat  = nb_fields;
  p->wins   = NULL;
  
  dat = U_malloc(nb_fields,data,"PLOT_getDistribution error code 2\n");
  
  for(field=0; field<nb_fields; field++){
    d = datas[field];
    nb_pt = d[0];
    /* find min and max */
    min = -1;
    max = 0;
    for(i=1;i<=nb_pt;i++){
      if(d[i] < min || min == -1)
	min = d[i];
      if(d[i] > max)
	max = d[i];
    }
    max = max + 0.1; /* interval is [x0,x1[ there is only nbbars */
    delta = (max - min)/nb_bars;

    /* initialize dat */
    dat[field].pdata = U_malloc(2*nb_bars,double,"PLOT_getDistribution error code 3\n");
    dat[field].nb = nb_bars;
    x = dat[field].x = dat[field].pdata;
    y = dat[field].y = dat[field].pdata + nb_bars;
    dat[field].z = 0;
    dat[field].title = fields[id_fields[field]];
    dat[field].style = PLOT_BOXES;
    
    y[0] = 0;
    x[0] = min + delta/2;
    for(i=1;i<nb_bars;i++){
      x[i] = x[i-1] + delta;
      y[i] = 0;
    }
    
    /* count data */
    for(i=1;i<=nb_pt;i++){
      y[(int)((d[i] - min)/delta)]++;
    }
    
    /* adjust to percents */
    //printf("%d %f %f %f\n",field,min,max,delta);
    delta = 100/(double)nb_pt;
    for(i=0;i<nb_bars;i++){
      //printf(" -- %d %f\n",i,y[i]);
      y[i] *= delta;
    }
  }
  p->dat = dat;
  return p;
}

int PLOT_close(plot* plot, ctrl *ctrl){
  int i;
  if(ctrl->multiple_win == YES){
    for(i=0;i<plot->w;i++){
      gnuplot_close(plot->wins[i]);
      plot->wins[i] = NULL;
    }
  }else{
    gnuplot_close(plot->win);
    plot->win = NULL;
  }
  return 1;
}

void PLOT_free(plot* plot, ctrl* ctrl){
  int i;
  for(i=0;i<plot->nbdat;i++){
    if(plot->dat[i].pdata != NULL)
      U_free("PLOT_free error code 1\n",&(plot->dat[i].pdata),LEND);
  }
  if(ctrl->multiple_win == YES){
    U_free("PLOT_free error code 2\n",&(plot->wins),LEND);
  }
  U_free("PLOT_free error code 3\n",&(plot->dat),&(plot),LEND);
}
